﻿using System;
using System.Windows;
using Gwn.Library.MvpVm.Configuration;
using Gwn.Library.MvpVm.Extensions;
using Gwn.Library.MvpVm.Interfaces;
using Gwn.Library.MvpVm.Loggers;
using Microsoft.Practices.Prism;
using Microsoft.Practices.Prism.Logging;
using Microsoft.Practices.Prism.Modularity;
using Microsoft.Practices.Prism.Regions;
using Microsoft.Practices.Prism.UnityExtensions;
using Microsoft.Practices.Unity;

namespace Gwn.Library.MvpVm.Base
{
    /// <summary>
    /// Bootstrapper
    /// </summary>
    public class GwnBootstrapper<T> : UnityBootstrapper, IBootstrapper
        where T : IShell
    {
        private IShell _shell;


        /// <summary>
        /// Initializes a new instance of the <see cref="GwnBootstrapper&lt;T&gt;"/> class.
        /// </summary>
        public GwnBootstrapper()
        {
            
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="GwnBootstrapper&lt;T&gt;"/> class.
        /// </summary>
        /// <param name="container">The container.</param>
        public GwnBootstrapper(IUnityContainer container)
        {
            Container = container;
        }

        /// <summary>
        /// Configures the <see cref="IModuleCatalog"/> used by Prism.
        /// </summary>
        protected override void ConfigureModuleCatalog()
        {
            // Define the default handler of MessageBoxShow to be
            // the MessageBox.Show delegate.   Unit test will set this
            // value to a delegate that does not require user interaction
            ClassBase.MessageBoxShow = (a, b, c) =>
            {
                return MessageBox.Show(a, b, c);
            };

            Logger.LogDebug("ConfigureModuleCatalog", GetType());
            base.ConfigureModuleCatalog();

            var moduleCatalog = ModuleCatalog as ModuleCatalog;
            if (moduleCatalog == null)
                throw new InvalidOperationException("Module Catalog is not available in GwnBootstrapper");

            AddModules(moduleCatalog);

        }

        /// <summary>
        /// Adds the modules.
        /// </summary>
        /// <param name="moduleCatalog">The module catalog.</param>
        protected virtual void AddModules(ModuleCatalog moduleCatalog)
        {

        }

        /// <summary>
        /// Loads the module on demand.
        /// </summary>
        /// <param name="moduleType">Type of the module.</param>
        protected void LoadModuleOnDemand(Type moduleType)
        {
            ((ModuleCatalog) ModuleCatalog).AddModule(
                new ModuleInfo
                    {
                        ModuleName = moduleType.Name,
                        ModuleType = moduleType.AssemblyQualifiedName,
                        InitializationMode = InitializationMode.OnDemand
                    });
        }


        /// <summary>
        /// Create the <see cref="ILoggerFacade"/> used by the bootstrapper.
        /// </summary>
        /// <returns></returns>
        /// <remarks>
        /// The base implementation returns a new TextLogger.
        /// </remarks>
        protected override ILoggerFacade CreateLogger()
        {
            return new DebugLogger();            
        }


        /// <summary>
        /// Used by the Phone so that we can get a reference to the 
        /// Shell since the MainPage.xaml.cs is the starting point
        /// </summary>
        /// <param name="shell">The shell.</param>
        public void Run(IShell shell)
        {
            _shell = shell;
            Run();
        }

        /// <summary>
        /// Configures the <see cref="IUnityContainer"/>. 
        /// May be overwritten in a derived class to add specific
        /// type mappings required by the application.
        /// </summary>
        protected override void ConfigureContainer()
        {
            Logger.LogDebug("ConfigureContainer", GetType());

            base.ConfigureContainer();

            // Global registrations
            Container
                .RegisterType<IAppConfig,AppConfig>(new ContainerControlledLifetimeManager())
                .RegisterInstance(Logger)

                // Since this is open source be sure to change these
                // so that your data file cannot be decrypted
                .RegisterInstance("Salt", "My Salt Code")
                .RegisterInstance("HashKey", "My Hash Code");
        }

        /// <summary>
        /// Creates the shell or main window of the application.
        /// </summary>
        /// <returns>The shell of the application.</returns>
        /// <remarks>
        /// If the returned instance is a <see cref="DependencyObject"/>, the
        /// <see cref="Bootstrapper"/> will attach the default <seealso cref="IRegionManager"/> of
        /// the application in its <see cref="RegionManager.RegionManagerProperty"/> attached property
        /// in order to be able to add regions by using the <seealso cref="RegionManager.RegionNameProperty"/>
        /// attached property from XAML.
        /// </remarks>
        protected override DependencyObject CreateShell()
        {
            Logger.LogDebug("ConfigureContainer", GetType());

            if (_shell == null)
                _shell = Container.Resolve<T>();

            Container.RegisterInstance(_shell);
            return (DependencyObject) _shell;
        }

        /// <summary>
        /// Initializes the shell.
        /// </summary>
        protected override void InitializeShell()
        {
            Logger.LogDebug("CreateShell", GetType());
            base.InitializeShell();

            #region DESKTOP

#if GWNDESKTOP

#if !GWNUNITTEST
            Application.Current.MainWindow=(Window)this.Shell;
            Application.Current.MainWindow.Show();
#endif

#endif
            #endregion

            #region SILVERLIGHT
#if GWNSILVERLIGHT
            Application.Current.RootVisual = (UIElement)this.Shell;
#endif
            #endregion

            #region PHONE
#if GWNPHONE
#endif
            #endregion

        }
    }
}
